
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Java并发工具包 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>Java并发工具包 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">Java 提供了 `java.util.concurrent` 包来解决并发编程中的问题，其主要目标是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主要目标包括四个方面：1. 简化并发编程，降低手动管理线程和同步的复杂度；2. 提高并发性能，通过线程池管理、锁优化和无锁编程模式提高效率；3. 保证线程安全，通过线程安全的集合类、锁和原子变量等工具减少常见错误；4. 增加可扩展性，设计时考虑高并发环境下的资源合理利用。</div>
          </div>
          <div class="card-source">来源: 并发工具包概述 -> 2. 并发工具包的主要目标</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">对比</div>
          <div class="card-question">在Java并发任务中，`Callable` 接口相较于 `Runnable` 接口有哪些核心区别和优势？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">对比</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`Callable` 是 `Runnable` 的扩展，其主要区别在于：1. `Callable` 的 `call()` 方法可以返回一个结果，而 `Runnable` 的 `run()` 方法没有返回值；2. `Callable` 的 `call()` 方法可以抛出受检异常（Exception），而 `Runnable` 的 `run()` 方法不能。这使得 `Callable` 更适用于需要获取执行结果或处理异常的复杂任务。</div>
          </div>
          <div class="card-source">来源: 并发工具包中的核心接口 -> 2. Callable 和 Runnable</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在关闭线程池时，`ExecutorService` 接口的 `shutdown()` 和 `shutdownNow()` 方法有何不同？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主要区别在于关闭的策略和紧急程度：`shutdown()` 方法会平滑地关闭线程池，它不再接收新的任务，但会继续执行已经提交到队列中的任务。而 `shutdownNow()` 方法会立即尝试关闭线程池，它不仅不接收新任务，还会尝试停止所有正在执行的任务，并返回等待队列中未执行的任务列表。</div>
          </div>
          <div class="card-source">来源: 并发工具包中的核心接口 -> 1. Executor 和 ExecutorService</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">`ThreadPoolExecutor` 提供了哪些常见的拒绝策略来处理超出其处理能力的任务？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当线程池和任务队列都满时，`ThreadPoolExecutor` 提供了四种常见的拒绝策略：1. `AbortPolicy`（默认）：直接抛出异常；2. `CallerRunsPolicy`：由提交任务的线程自己来执行该任务；3. `DiscardPolicy`：直接丢弃该任务；4. `DiscardOldestPolicy`：丢弃任务队列中最旧的任务，然后尝试重新提交当前任务。</div>
          </div>
          <div class="card-source">来源: 线程池（Executor Framework） -> 5. 线程池的配置参数</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">`ConcurrentHashMap` 是如何实现高并发性能的？其核心机制是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`ConcurrentHashMap` 的核心机制是分段锁（Segment Locking）。它将内部数据结构分成多个段（Segment），每个段都有自己的锁。当一个线程需要修改数据时，只需锁定对应的段，而其他线程可以并发地访问或修改其他段的数据，从而大大减少了锁竞争。此外，其读操作几乎不需要加锁，进一步提升了性能。</div>
          </div>
          <div class="card-source">来源: 并发集合类 -> 1. ConcurrentHashMap</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">`CopyOnWriteArrayList` 的工作原理是什么？它最适合应用于哪种类型的并发场景？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`CopyOnWriteArrayList` 的工作原理是“写时复制”。当对列表进行修改操作（如add、remove）时，它不会直接在原数组上修改，而是先创建一个原数组的副本，在副本上进行修改，完成后再将引用指向新的数组。由于读操作总是在原数组上进行且无需加锁，因此它最适用于“读多写少”的并发场景。</div>
          </div>
          <div class="card-source">来源: 并发集合类 -> 2. CopyOnWriteArrayList</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">Java中的原子变量类（如`AtomicInteger`）是如何在不使用锁的情况下保证线程安全的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">原子变量类通过底层的 CAS（Compare-And-Swap，比较并交换）操作来保证原子性。CAS是一种硬件级别的原子指令，它包含三个操作数：内存位置、期望值和新值。只有当内存位置的当前值与期望值相同时，才会将该位置的值更新为新值。整个比较和交换过程是一个不可中断的原子操作，从而避免了使用锁带来的性能开销。</div>
          </div>
          <div class="card-source">来源: 原子变量 -> 3. CAS（Compare-And-Swap）操作</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">对比</div>
          <div class="card-question">同步工具 `CountDownLatch` 和 `CyclicBarrier` 都可以用于线程同步，它们之间最主要的区别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">对比</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">最主要的区别在于可重用性。`CountDownLatch` 是一次性的，其计数器一旦减到零就不能再被重置或复用，主要用于一个或多个线程等待其他线程完成一组操作。而 `CyclicBarrier` 是可重用的，当一组线程到达屏障点后，屏障可以被重置以用于下一组线程，适用于需要分阶段同步执行的循环任务。</div>
          </div>
          <div class="card-source">来源: 锁与同步工具 -> 2.2 CyclicBarrier</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">`ForkJoinPool` 使用了什么核心算法来提高多核CPU的利用率，避免线程闲置？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`ForkJoinPool` 使用了“工作窃取算法”（work stealing）。每个工作线程都维护一个双端队列来存放任务。当一个线程完成了自己队列中的所有任务后，它会从其他线程队列的末尾“窃取”一个任务来执行。这种机制可以有效地平衡各线程的负载，最大化CPU的利用率。</div>
          </div>
          <div class="card-source">来源: 并行流与 ForkJoinPool -> 2.3 ForkJoinPool 的性能</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">Java中的`ReadWriteLock`（读写锁）相比于传统的排他锁（如`ReentrantLock`）有何优势，适用于何种场景？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`ReadWriteLock` 的优势在于它将读操作和写操作的锁分离开来。它允许多个线程同时获取读锁并访问资源，但写锁是独占的。这种机制使得它特别适用于“读多写少”的场景，例如缓存系统或配置信息读取，能够显著提高程序的并发吞吐量。</div>
          </div>
          <div class="card-source">来源: 锁与同步工具 -> 1.2 ReadWriteLock</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">`Semaphore`（信号量）在并发编程中的主要作用是什么？请提供一个典型的应用场景。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`Semaphore` 的主要作用是控制对某一共享资源的并发访问线程数量。它维护一个许可（permit）计数器，线程在访问资源前必须获取一个许可，使用完毕后释放许可。这可以用来限制对资源的并发访问。一个典型的应用场景是控制数据库连接池中可用连接的数量。</div>
          </div>
          <div class="card-source">来源: 并发工具包中的核心接口 -> 6. Semaphore</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">专门用于执行定时和周期性任务的线程池是什么？它提供了哪几种核心的调度方法？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">专门用于执行定时和周期性任务的线程池是 `ScheduledExecutorService`。它提供了三种核心的调度方法：1. `schedule()`：在指定的延迟后执行一次任务；2. `scheduleAtFixedRate()`：以固定的频率周期性执行任务；3. `scheduleWithFixedDelay()`：在上一次任务执行完成后，等待一个固定的延迟时间，再执行下一次任务。</div>
          </div>
          <div class="card-source">来源: 任务调度与执行 -> 2.2 ScheduledExecutorService</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
